(define-module (web-path-handling)
  #:export (static-assets-dir-name
            static-assets-dir-path
            safe-path?
            static-asset-path?
            safe/static-asset-path?
            safe/existing/static-asset-path?))


(use-modules
 ((srfi srfi-1) #:prefix srfi-1:)
 ((logging) #:prefix log:)
 (path-handling))


;; Define some bindings, which are required for security
;; reasons.

(define static-assets-dir-name "static")
(define static-assets-dir-path (canonicalize-path static-assets-dir-name))


(define safe-path?
  (λ (path required-parent-path)
    (and
     ;; outright refuse to work with a complex path
     (not (complex-path? path))
     ;; must be inside the static assets directory
     (log:debug "subpath? of" (absolute-path path) "and" required-parent-path)
     (subpath? (absolute-path path) required-parent-path))))


(define static-asset-path?
  (λ (path)
    "Check if the path's first part is the static
directory. Warning: This predicate does not guarantee it to
be a safe path."
    (let ([path-parts (path-split path)])
      (string=? (srfi-1:first path-parts) static-assets-dir-name))))


(define safe/static-asset-path?
  (λ (path)
    (log:debug "checking whether path is static asset path")
    (log:debug "checking for safety of path")
    (and (static-asset-path? path)
         (safe-path? path static-assets-dir-path))))


(define safe/existing/static-asset-path?
  (λ (path)
    (log:debug "checking for safety and existence of path")
    (and (file-exists? path)
         (safe/static-asset-path? path))))
